package com.longge.bigfile.service.impl;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Set;

import org.springframework.web.multipart.MultipartFile;

import com.longge.bigfile.config.AmazonS3Configuration.S3Config;
import com.longge.bigfile.dto.request.BaseDto;
import com.longge.bigfile.util.S3ClientUtils;
import com.longge.common.util.ForEachUtils;

import lombok.extern.slf4j.Slf4j;
import software.amazon.awssdk.core.sync.RequestBody;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.model.CompleteMultipartUploadRequest;
import software.amazon.awssdk.services.s3.model.CompleteMultipartUploadResponse;
import software.amazon.awssdk.services.s3.model.CompletedMultipartUpload;
import software.amazon.awssdk.services.s3.model.CompletedPart;
import software.amazon.awssdk.services.s3.model.CreateMultipartUploadRequest;
import software.amazon.awssdk.services.s3.model.CreateMultipartUploadResponse;
import software.amazon.awssdk.services.s3.model.PutObjectRequest;
import software.amazon.awssdk.services.s3.model.PutObjectResponse;
import software.amazon.awssdk.services.s3.model.UploadPartRequest;
import software.amazon.awssdk.services.s3.model.UploadPartResponse;

/**
 * @author roger yang
 * @date 10/31/2019
 * S3 API:
    1、S3Client.createMultipartUpload
    2、S3Client.uploadPart
    3、S3Client.completeMultipartUpload
    4、S3Client.putObject
 */
@Slf4j
public class S3ProcessServiceImpl extends AbstractProcessServiceImpl {
	
    private static ThreadLocal<S3Client> clientLocal = new ThreadLocal<>();
    private static ThreadLocal<S3Config> configLocal = new ThreadLocal<>();
    
    @Override
	public void setThreadLocal(BaseDto dto) {
    	S3Client s3Client = S3ClientUtils.getClient(dto.getSys());
        clientLocal.set(s3Client);
        S3Config s3Config = S3ClientUtils.getConfig(dto.getSys());
        configLocal.set(s3Config);
	}

	@Override
	public void removeThreadLocal() {
		clientLocal.remove();
        configLocal.remove();
	}

	@Override
	public String initUpload(String realFileKey) {
        CreateMultipartUploadRequest createMultipartUploadRequest = CreateMultipartUploadRequest.builder()
            .bucket(configLocal.get().getBucketName()).key(realFileKey)
            .build();
        CreateMultipartUploadResponse initResp  = clientLocal.get().createMultipartUpload(createMultipartUploadRequest);
        if(null != initResp) {
            return initResp.uploadId();
        }
		return null;
	}

	@Override
	public String uploadRealFile(MultipartFile file, String realFileKey) {
		try (InputStream is = file.getInputStream(); ){
            PutObjectRequest puRequest = PutObjectRequest.builder()
                .bucket(configLocal.get().getBucketName())
                .key(realFileKey)
                .build();
            RequestBody reqBody = RequestBody.fromInputStream(is, file.getSize());
            PutObjectResponse result = clientLocal.get().putObject(puRequest, reqBody);
            
            if(!Objects.isNull(result)) {
                return result.eTag();
            }
        } catch (Exception e) {
            log.error("upload fail", e);
        }
        return null;
	}

	@Override
	public String uploadPartFile(MultipartFile file, String realFileKey, String uploadId, int sliceIndex) {
		try(InputStream is = file.getInputStream();) {
            UploadPartRequest request = UploadPartRequest.builder()
                .bucket(configLocal.get().getBucketName())
                .key(realFileKey)
                .partNumber(sliceIndex+1)
                .uploadId(uploadId)
                .build();
            
            UploadPartResponse result = clientLocal.get().uploadPart(request, RequestBody.fromInputStream(is, file.getSize()));
            if(!Objects.isNull(result)) {
                return result.eTag();
            }
        } catch (Exception e) {
            log.error("upload fail", e);
        }
        return null;
	}

	@Override
	public String completedUpload(String uploadId, String realFileKey, Set<String> endETags) {
		List<CompletedPart> parts = new ArrayList<>();
        ForEachUtils.forEach(0, endETags,(index, item) -> {
            CompletedPart part = CompletedPart.builder().partNumber(index+1).eTag(item).build();
            parts.add(part);
        });
        CompletedMultipartUpload completedMultipartUpload = CompletedMultipartUpload.builder().parts(parts).build();
        CompleteMultipartUploadRequest request = CompleteMultipartUploadRequest.builder()
            .bucket(configLocal.get().getBucketName())
            .key(realFileKey)
            .uploadId(uploadId)
            .multipartUpload(completedMultipartUpload)
            .build();
        try {
            CompleteMultipartUploadResponse result = clientLocal.get().completeMultipartUpload(request);
            if(null != result) {
                return result.eTag();
            }
        } catch (Exception e) {
            log.error("s3 complete file error", e);
        }
		return null;
	}
}
